package com.pactera.asmp.server.job;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.pactera.asmp.server.common.constants.ResultCode;
import com.pactera.asmp.server.common.constants.TaskStatus;
import com.pactera.asmp.server.common.exception.CustomException;
import com.pactera.asmp.server.common.utils.DateUtil;
import com.pactera.asmp.server.dao.TaskDeviceMapper;
import com.pactera.asmp.server.dao.TaskMapper;
import com.pactera.asmp.server.entity.TaskDTO;
import com.pactera.asmp.server.entity.TaskDevice;
import com.pactera.asmp.server.entity.TaskDeviceExample;
import com.pactera.asmp.server.job.dispatch.impl.task.TaskManager;
import com.pactera.asmp.server.pojo.ScriptInfo2;
import com.pactera.asmp.server.pojo.TaskDeviceInfo;
import com.pactera.asmp.server.pojo.WSScriptMessage;
import com.pactera.asmp.server.service.IDeviceServcie;
import com.pactera.asmp.server.service.ScriptInfoServcieImpl;
import com.pactera.asmp.server.service.TaskService;

import com.pactera.asmp.server.vo.TaskCreateRequest;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;


@Slf4j
@Component
public class AutoTestJobV2 implements BaseJob {
    @Autowired
    @Lazy
    private TaskService taskService;
    @Autowired
    private IDeviceServcie iDeviceServcie;
    @Autowired
    private ScriptInfoServcieImpl mScriptInfoServcieImpl;
    @Autowired
    private TaskManager taskManager;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private TaskDeviceMapper taskDeviceMapper;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        Integer taskId = null;
        try {
            taskId = Integer.valueOf(context.getTrigger().getJobKey().getGroup());
            log.info("-----------*******-----------AutoTestJob 事件开始执行时间: {}   tastId:{}      getJobKey().getName():{}",DateUtil.now().toString() , taskId , context.getTrigger().getJobKey().getName());

            TaskDTO taskHist = taskService.getTaskHistoryById(taskId);
            if (taskHist == null) {
                log.error("AutoTestJob execute task = null.");
                taskService.removeTaskNotFoundJob(taskId);
                return;
            }
            TaskDTO task = taskMapper.getTaskById(taskHist.getParentId());
            if (task == null) {
                log.error("AutoTestJob execute task = null.");
                taskService.removeTaskNotFoundJob(taskId);
                return;
            }
            // 移除已完成的任务
            if(task.getStatus().intValue() == TaskStatus.TASK_COMPLETE.getValue()
                    || task.getStatus().intValue() == TaskStatus.TASK_CANCEL.getValue()
                    || task.getStatus().intValue() == TaskStatus.TASK_NO_DEVICE_FAIL.getValue()) {
                log.error("AutoTestJob execute task complete、cancel or fail. status:{}", task.getStatus().intValue());
                taskService.removeTaskNotFoundJob(taskId);
                return;
            }
            if(task.getExeStartTime()!=null && task.getExeEndTime()!=null){
                if(context.getFireTime().before(com.pactera.asmp.server.utils.DateUtil.toDate(task.getExeStartTime()))
                        ||context.getFireTime().after(com.pactera.asmp.server.utils.DateUtil.toDate(task.getExeEndTime()))){
                    //在执行时间范围之外
//                    if(task.getStatus() == 1
                    if(context.getFireTime().after(com.pactera.asmp.server.utils.DateUtil.toDate(task.getExeEndTime()))){
                        log.info("定时任务已经完成: {}   tastId:{}",DateUtil.now().toString() , taskId);
                        task.setStatus(3);
                        taskMapper.update(task);
                    }
                    return;
                }
            }
            if(task.getExecTime() != null) {
                Long intervalTime = context.getNextFireTime().getTime() - context.getFireTime().getTime();
                //防止时间毫秒误差
                intervalTime = intervalTime - 10000;
                //上次执行时间时间差
                Long minusTime = System.currentTimeMillis() - task.getExecTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                if (minusTime < intervalTime) {
                    //当前时间周期已有执行
                    log.info("当前时间周期已有执行: {}   minusTime:{}, intervalTime:{}",DateUtil.now().toString() , minusTime, intervalTime);
                    return;
                }
            }
            TaskCreateRequest request = buildRequest(task, taskHist.getId());
            if(request == null){
                return;
            }
            log.info("创建新任务: {}   minusTime:{}, intervalTime:{}",DateUtil.now().toString() , JSONObject.toJSONString(request.getTaskDTO()), request.getTaskDTO().getUserId());
            taskService.createTask(request, request.getTaskDTO(), request.getTaskDTO().getUserId());
            task.setExecTime(LocalDateTime.now());
            taskMapper.update(task);

        }catch (Exception e){
            log.info(e.getMessage());
            // 执行失败处理
            this.taskService.taskFailById(taskId,e.getMessage());
        }
    }

    private TaskCreateRequest buildRequest(TaskDTO parentTask, Integer taskHistId){
        TaskCreateRequest request = new TaskCreateRequest();
        TaskDTO taskDTO = new TaskDTO();
        BeanUtils.copyProperties(parentTask, taskDTO);
        taskDTO.setId(null);
        taskDTO.setCreateTime(LocalDateTime.now());
        //立即执行
        taskDTO.setCycleType(2);
        taskDTO.setParentId(parentTask.getId());
        request.setTaskDTO(taskDTO);

        List<TaskDevice> list = getTaskDeviceListById(taskHistId);
        if(CollectionUtils.isEmpty(list)){
            return null;
        }
        List<TaskDeviceInfo> duidList = new ArrayList<>();
        for(TaskDevice taskDevice : list){
            TaskDeviceInfo tdi = new TaskDeviceInfo();
            tdi.setDuid(taskDevice.getDuid());
            tdi.setAuxDuid(taskDevice.getAuxDuid());
            duidList.add(tdi);
        }
        request.setDuidList(duidList);
        return  request;
    }

    private List<TaskDevice> getTaskDeviceListById(Integer taskId){
        TaskDeviceExample taskDeviceExample = new TaskDeviceExample();
        taskDeviceExample.createCriteria().andTaskIdEqualTo(Long.valueOf(taskId)).andIsDeletedEqualTo(0);
        return taskDeviceMapper.selectByExample(taskDeviceExample);
    }

    private List<String> orderScripts(List<Integer> orderIds,List<ScriptInfo2> scriptInfos){
        if(CollectionUtils.isEmpty(orderIds) || CollectionUtils.isEmpty(scriptInfos)) throw new CustomException(ResultCode.DATA_IS_WRONG);
        List<String> orderList = new ArrayList<>();
        for (Integer id : orderIds){
            for (ScriptInfo2 scriptInfo : scriptInfos){
                if( id.intValue() ==  scriptInfo.getId().intValue()){
                    orderList.add(JSON.toJSONString(scriptInfo));
                    break;
                }
            }
        }
        return orderList;
    }

}
